﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using Novacode;
using System.Windows.Forms;

namespace AMOOF {
    public class ReportGenerator {

        private DocX doc;

        public bool GenerateDocument() {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "Word Document |*.docx";
            DialogResult dr = sfd.ShowDialog();
            if (dr.Equals(DialogResult.Cancel)) {
                return false;
            }
            else if (sfd.FileName.Trim().Equals("")) {
                return false;
            }
            else {
                try {
                    doc = DocX.Create(sfd.FileName);
                    this.ExportDocument();
                    return true;
                }
                catch (Exception e) {
                    Program.log(e.Message + "\r\n" + e.StackTrace);
                    return false;
                }
            }
            return false;
        }

        private void ExportDocument() {
            try {
                Title();
                DataSetStatistics();
                DataSetCTEVaR();
                PDFs();

                doc.Save();
                doc.Dispose();
            }
            catch (Exception) {

                throw new Exception("Failed to export");
            }
        }

        private void Title() {
            Paragraph p = doc.InsertParagraph();
            p.Alignment = Alignment.center;
            p.AppendLine("AMOOF Risk Analysis Report").Bold().FontSize(36);
            p.AppendLine(DateTime.Today.ToString());
            p.AppendLine("Report generated by AMOOF 2.0");
            p.AppendLine("\n");
        }

        private void DataSetStatistics() {
            Statistics stats = FormAMOOF.Instance.GetStatistics();
            Paragraph p = doc.InsertParagraph();
            Table desc1 = doc.InsertTable(5, 2);
            desc1.Design = TableDesign.TableGrid;
            desc1.Rows[0].MergeCells(0, 1);
            desc1.Rows[0].Height = 24.0;

            desc1.Rows[0].Cells[0].Paragraphs[0].Append("Descriptive Statistics").FontSize(16).Bold().Alignment = Alignment.center;
            desc1.Rows[1].Cells[0].Paragraphs[0].Append("Mean").FontSize(10);
            desc1.Rows[2].Cells[0].Paragraphs[0].Append("Median").FontSize(10);
            desc1.Rows[3].Cells[0].Paragraphs[0].Append("Q1").FontSize(10);
            desc1.Rows[4].Cells[0].Paragraphs[0].Append("Q3").FontSize(10);

            desc1.Rows[1].Cells[1].Paragraphs[0].Append(stats.Mean.ToString()).FontSize(10);
            desc1.Rows[2].Cells[1].Paragraphs[0].Append(stats.Median.ToString()).FontSize(10);
            desc1.Rows[3].Cells[1].Paragraphs[0].Append(stats.FirstQuartile.ToString()).FontSize(10);
            desc1.Rows[4].Cells[1].Paragraphs[0].Append(stats.ThirdQuartile.ToString()).FontSize(10);

            Paragraph p1 = doc.InsertParagraph();

            Table desc2 = doc.InsertTable(9, 2);
            desc2.Design = TableDesign.TableGrid;
            desc2.Rows[0].MergeCells(0, 1);
            desc2.Rows[0].Height = 24.0;


            desc2.Rows[0].Cells[0].Paragraphs[0].Append("Moments").FontSize(16).Bold().Alignment = Alignment.center;
            desc2.Rows[1].Cells[0].Paragraphs[0].Append("1st").FontSize(10);
            desc2.Rows[2].Cells[0].Paragraphs[0].Append("2nd").FontSize(10);
            desc2.Rows[3].Cells[0].Paragraphs[0].Append("3rd").FontSize(10);
            desc2.Rows[4].Cells[0].Paragraphs[0].Append("4th").FontSize(10);
            desc2.Rows[5].Cells[0].Paragraphs[0].Append("-1st").FontSize(10);
            desc2.Rows[6].Cells[0].Paragraphs[0].Append("-2nd").FontSize(10);
            desc2.Rows[7].Cells[0].Paragraphs[0].Append("-3rd").FontSize(10);
            desc2.Rows[8].Cells[0].Paragraphs[0].Append("-4th").FontSize(10);

            desc2.Rows[1].Cells[1].Paragraphs[0].Append(stats.DataMoments[1].ToString()).FontSize(10);
            desc2.Rows[2].Cells[1].Paragraphs[0].Append(stats.DataMoments[2].ToString()).FontSize(10);
            desc2.Rows[3].Cells[1].Paragraphs[0].Append(stats.DataMoments[3].ToString()).FontSize(10);
            desc2.Rows[4].Cells[1].Paragraphs[0].Append(stats.DataMoments[4].ToString()).FontSize(10);
            desc2.Rows[5].Cells[1].Paragraphs[0].Append(stats.DataMoments[-1].ToString()).FontSize(10);
            desc2.Rows[6].Cells[1].Paragraphs[0].Append(stats.DataMoments[-2].ToString()).FontSize(10);
            desc2.Rows[7].Cells[1].Paragraphs[0].Append(stats.DataMoments[-3].ToString()).FontSize(10);
            desc2.Rows[8].Cells[1].Paragraphs[0].Append(stats.DataMoments[-4].ToString()).FontSize(10);
        }

        private void DataSetCTEVaR() {
            Statistics stats = FormAMOOF.Instance.GetStatistics();
            Paragraph p = doc.InsertParagraph();
            Dictionary<int, double> discCTE = stats.CTEs;
            Dictionary<int, double> discVaR = stats.VaRs;
            p.AppendLine("Data Set Conditional Tail Expectations and Value at Risks:").Bold();
            Table varcte1 = doc.AddTable(3, 12);
            Table varcte2 = doc.AddTable(3, 12);

            varcte1.Alignment = Alignment.center;
            varcte1.Design = TableDesign.LightGrid;
            varcte2.Alignment = Alignment.center;
            varcte2.Design = TableDesign.LightGrid;

            varcte1.Rows[1].Cells[0].Paragraphs[0].Append("VaR").Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte1.Rows[2].Cells[0].Paragraphs[0].Append("CTE").Font(FontFamily.GenericSansSerif).FontSize(8);

            varcte1.Rows[0].Cells[1].Paragraphs[0].Append("1%").Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte1.Rows[1].Cells[1].Paragraphs[0].Append(String.Format("{0:0.000}", discVaR[1])).Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte1.Rows[2].Cells[1].Paragraphs[0].Append(String.Format("{0:0.000}", discCTE[1])).Font(FontFamily.GenericSansSerif).FontSize(8);

            varcte2.Rows[1].Cells[0].Paragraphs[0].Append("VaR").Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte2.Rows[2].Cells[0].Paragraphs[0].Append("CTE").Font(FontFamily.GenericSansSerif).FontSize(8);

            varcte2.Rows[0].Cells[11].Paragraphs[0].Append("99%").Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte2.Rows[1].Cells[11].Paragraphs[0].Append(String.Format("{0:0.000}", discVaR[99])).Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte2.Rows[2].Cells[11].Paragraphs[0].Append(String.Format("{0:0.000}", discCTE[99])).Font(FontFamily.GenericSansSerif).FontSize(8);

            for (int i = 2; i < 12; i++) {
                varcte1.Rows[0].Cells[i].Paragraphs[0].Append(((i - 1) * 5).ToString() + "%").Font(FontFamily.GenericSansSerif).FontSize(8);
                varcte1.Rows[1].Cells[i].Paragraphs[0].Append(String.Format("{0:0.000}", discVaR[((i - 1) * 5)])).Font(FontFamily.GenericSansSerif).FontSize(8);
                varcte1.Rows[2].Cells[i].Paragraphs[0].Append(String.Format("{0:0.000}", discCTE[((i - 1) * 5)])).Font(FontFamily.GenericSansSerif).FontSize(8);

                varcte2.Rows[0].Cells[i - 1].Paragraphs[0].Append((((i - 2) * 5) + 50).ToString() + "%").Font(FontFamily.GenericSansSerif).FontSize(8);
                varcte2.Rows[1].Cells[i - 1].Paragraphs[0].Append(String.Format("{0:0.000}", discVaR[(((i - 2) * 5) + 50)])).Font(FontFamily.GenericSansSerif).FontSize(8);
                varcte2.Rows[2].Cells[i - 1].Paragraphs[0].Append(String.Format("{0:0.000}", discCTE[(((i - 2) * 5) + 50)])).Font(FontFamily.GenericSansSerif).FontSize(8);

            }

            p.InsertTableAfterSelf(varcte1);

            Paragraph p2 = doc.InsertParagraph();
            p2.AppendLine();
            p2.InsertTableAfterSelf(varcte2);
            
        }

        private void PDFs() {
            Histogram hist = FormAMOOF.Instance.GetHistogram();
            hist.ImageSize = new Size(600, 330);
            Paragraph p = doc.InsertParagraph();
            p.InsertPageBreakBeforeSelf();
            Novacode.Image img;
            Picture pic;
            Bitmap bmp;
            FileStream str;
            var reports = FormAMOOF.Instance.GetReports();

            foreach (var kvp in reports) {
                if (!kvp.Value.InReport) { continue; }
                p = doc.InsertParagraph();
                p.AppendLine(kvp.Value.PDF.name + " (Relative Error: " + kvp.Value.PDF.AverageError + "):").FontSize(14);
                hist.ClearPDFs();
                hist.AddPDF(kvp.Value.PDF, Color.Black);
                bmp = hist.GetHistogram();
                bmp.Save(kvp.Value.PDF.name + ".bmp");
                str = new FileStream(kvp.Value.PDF.name + ".bmp", FileMode.Open);
                img = doc.AddImage(str);
                pic = img.CreatePicture();
                p.AppendPicture(pic);
                bmp.Dispose();
                str.Close();
                str.Dispose();
                File.Delete(kvp.Value.PDF.name + ".bmp");
                p.InsertTableAfterSelf(getGreeks(kvp.Value.PDF.Greeks));

                Paragraph p0 = doc.InsertParagraph();
                p0.InsertTableAfterSelf(getMoments(kvp.Value.PDF));

                Paragraph p2 = doc.InsertParagraph();
                Table[] tables = integCTEVAR(kvp.Value);

                p2.InsertTableAfterSelf(tables[0]);
                Paragraph p3 = doc.InsertParagraph();
                p3.AppendLine();
                p3.InsertTableAfterSelf(tables[1]);
                doc.InsertParagraph().InsertPageBreakAfterSelf();
            }
        }

        private Table getGreeks(Dictionary<PDF.Greek, double> g) {
            Table greeks = doc.AddTable(g.Count + 1, 2);
            greeks.Design = TableDesign.TableGrid;
            greeks.Rows[0].MergeCells(0, 1);
            greeks.Rows[0].Height = 24.0;
            greeks.Rows[0].Cells[0].Paragraphs[0].Append("Greeks").FontSize(16).Bold().Alignment = Alignment.center;
            int i = 1;
            foreach (var kvp in g) {
                greeks.Rows[i].Cells[0].Paragraphs[0].Append(kvp.Key.ToString()).FontSize(10);
                greeks.Rows[i].Cells[1].Paragraphs[0].Append(kvp.Value.ToString()).FontSize(10);
                i++;
            }

            return greeks;
        }

        private Table getMoments(PDF pdf) {
            Table moments = doc.AddTable(9, 2);
            moments.Design = TableDesign.TableGrid;
            moments.Rows[0].MergeCells(0, 1);
            moments.Rows[0].Height = 24.0;
            moments.Rows[0].Cells[0].Paragraphs[0].Append("Moments").FontSize(16).Bold();
            moments.Rows[0].Cells[0].Paragraphs[0].Alignment = Alignment.center;
            moments.Rows[1].Cells[0].Paragraphs[0].Append("1st").FontSize(10);
            moments.Rows[2].Cells[0].Paragraphs[0].Append("2nd").FontSize(10);
            moments.Rows[3].Cells[0].Paragraphs[0].Append("3rd").FontSize(10);
            moments.Rows[4].Cells[0].Paragraphs[0].Append("4th").FontSize(10);
            moments.Rows[5].Cells[0].Paragraphs[0].Append("-1st").FontSize(10);
            moments.Rows[6].Cells[0].Paragraphs[0].Append("-2nd").FontSize(10);
            moments.Rows[7].Cells[0].Paragraphs[0].Append("-3rd").FontSize(10);
            moments.Rows[8].Cells[0].Paragraphs[0].Append("-4th").FontSize(10);
            moments.Rows[1].Cells[1].Paragraphs[0].Append("" + pdf.Moments[1]).FontSize(10);
            moments.Rows[2].Cells[1].Paragraphs[0].Append("" + pdf.Moments[2]).FontSize(10);
            moments.Rows[3].Cells[1].Paragraphs[0].Append("" + pdf.Moments[3]).FontSize(10);
            moments.Rows[4].Cells[1].Paragraphs[0].Append("" + pdf.Moments[4]).FontSize(10);
            moments.Rows[5].Cells[1].Paragraphs[0].Append("" + pdf.Moments[-1]).FontSize(10);
            moments.Rows[6].Cells[1].Paragraphs[0].Append("" + pdf.Moments[-2]).FontSize(10);
            moments.Rows[7].Cells[1].Paragraphs[0].Append("" + pdf.Moments[-3]).FontSize(10);
            moments.Rows[8].Cells[1].Paragraphs[0].Append("" + pdf.Moments[-4]).FontSize(10);
            return moments;
        }

        private Table[] integCTEVAR(Report r) {
            

            Table varcte1 = doc.AddTable(4, 12);
            Table varcte2 = doc.AddTable(4, 12);

            varcte1.Alignment = Alignment.center;
            varcte1.Design = TableDesign.TableGrid;
            varcte2.Alignment = Alignment.center;
            varcte2.Design = TableDesign.TableGrid;

            varcte1.Rows[1].Cells[0].Paragraphs[0].Append("VaR").Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte1.Rows[2].Cells[0].Paragraphs[0].Append("LCTE").Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte1.Rows[3].Cells[0].Paragraphs[0].Append("RCTE").Font(FontFamily.GenericSansSerif).FontSize(8);

            varcte1.Rows[0].Cells[1].Paragraphs[0].Append("1%").Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte1.Rows[1].Cells[1].Paragraphs[0].Append(String.Format("{0:0.000}", r.Integral.getPercentile(1).var)).Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte1.Rows[2].Cells[1].Paragraphs[0].Append(String.Format("{0:0.000}", r.Integral.getPercentile(1).leftCte)).Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte1.Rows[3].Cells[1].Paragraphs[0].Append(String.Format("{0:0.000}", r.Integral.getPercentile(1).rightCte)).Font(FontFamily.GenericSansSerif).FontSize(8);

            varcte2.Rows[1].Cells[0].Paragraphs[0].Append("VaR").Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte2.Rows[2].Cells[0].Paragraphs[0].Append("LCTE").Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte2.Rows[3].Cells[0].Paragraphs[0].Append("RCTE").Font(FontFamily.GenericSansSerif).FontSize(8);

            varcte2.Rows[0].Cells[11].Paragraphs[0].Append("99%").Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte2.Rows[1].Cells[11].Paragraphs[0].Append(String.Format("{0:0.000}", r.Integral.getPercentile(99).var)).Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte2.Rows[2].Cells[11].Paragraphs[0].Append(String.Format("{0:0.000}", r.Integral.getPercentile(99).leftCte)).Font(FontFamily.GenericSansSerif).FontSize(8);
            varcte2.Rows[3].Cells[11].Paragraphs[0].Append(String.Format("{0:0.000}", r.Integral.getPercentile(99).rightCte)).Font(FontFamily.GenericSansSerif).FontSize(8);

            for (int i = 2; i < 12; i++) {
                varcte1.Rows[0].Cells[i].Paragraphs[0].Append(((i - 1) * 5).ToString() + "%").Font(FontFamily.GenericSansSerif).FontSize(8);
                varcte1.Rows[1].Cells[i].Paragraphs[0].Append(String.Format("{0:0.000}", r.Integral.getPercentile(((i - 1) * 5)).var)).Font(FontFamily.GenericSansSerif).FontSize(8);
                varcte1.Rows[2].Cells[i].Paragraphs[0].Append(String.Format("{0:0.000}", r.Integral.getPercentile(((i - 1) * 5)).leftCte)).Font(FontFamily.GenericSansSerif).FontSize(8);
                varcte1.Rows[3].Cells[i].Paragraphs[0].Append(String.Format("{0:0.000}", r.Integral.getPercentile(((i - 1) * 5)).rightCte)).Font(FontFamily.GenericSansSerif).FontSize(8);

                varcte2.Rows[0].Cells[i - 1].Paragraphs[0].Append((((i - 2) * 5) + 50).ToString() + "%").Font(FontFamily.GenericSansSerif).FontSize(8);
                varcte2.Rows[1].Cells[i - 1].Paragraphs[0].Append(String.Format("{0:0.000}", r.Integral.getPercentile((((i - 2) * 5) + 50)).var)).Font(FontFamily.GenericSansSerif).FontSize(8);
                varcte2.Rows[2].Cells[i - 1].Paragraphs[0].Append(String.Format("{0:0.000}", r.Integral.getPercentile((((i - 2) * 5) + 50)).leftCte)).Font(FontFamily.GenericSansSerif).FontSize(8);
                varcte2.Rows[3].Cells[i - 1].Paragraphs[0].Append(String.Format("{0:0.000}", r.Integral.getPercentile((((i - 2) * 5) + 50)).rightCte)).Font(FontFamily.GenericSansSerif).FontSize(8);
            }

            Table[] tables = { varcte1, varcte2 };
            return tables;
        }
    }
}
